Project in opdracht van NWB projectteam, uitgevoerd door RWS Datalab.

Team:
Martijn Koole - Data Scientist
Daan van der Maas - Data Scientist
Jan Quist - Data Scientist
Steven van Gelder - Product manager
Vikash Rambaran - Product Owner

Data laden en preprocessing

Onderstaande code importeert alle benodigde libraries en functies en laadt vervolgens de gebruikte data. Er is een uitsnede gemaakt van het NWB Wegvakken bestand van 01-06-2017 rondom Gouda. Vervolgens is een zelfde uitsnede gemaakt voor de Basemap die verkregen is via BeMobile (gebaseerd op Open Street Map, OSM). De uitsnede is in eerste instantie gemaakt om de rekentijd kort te houden tijdens ontwikkelen/testen. Dat gebeurt in het script read_fcd.R. Later kunnen dezelfde scripts gebruikt worden voor om over heel Nederland verschillen te detecteren.

Om het NWB bestand te kunnen vergelijken zullen deze op elkaar gemapt moeten worden. Hiervoor is voor ieder ieder lijnsegment uit de OSM basemap gezocht naar een ‘nearest neighbor’ in het NWB. Met behulp van de afstand tot de nearest neighbor kunnen afwijkingen worden gedetecteerd. Voorbeeld: Objecten in de OSM basemap die geen nearest neighbor in het NWB hebben binnen een bepaalde marge kunnen duiden op missende/onjuiste informatie in het NWB. Andersom (NWB object zonder OSM nearest neighbor) duidt op een weg die wel in NWB bestaat, maar niet in de OSM basemap. Om de afstand te bepalen tussen een object in de OSM basemap en een object in NWB, is gebruik gemaakt van een afgeleide van de Hausdorff distance. Hiervoor is eerst nog enige bewerking gedaan.

#Eerst worden beide shapes omgezet naar RD coordinaten, t.b.v. eenheid meter
rd<- "+proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.999908 +x_0=155000 +y_0=463000 +ellps=bessel +units=m +towgs84=565.2369,50.0087,465.658,-0.406857330322398,0.350732676542563,-1.8703473836068,4.0812 +no_defs"

nwb_select<- spTransform(nwb_select,rd)
basemap_select<- spTransform(basemap_select,rd)

Equidistant

Beide bestanden bestaan uit Polyline shapes, maar de OSM basemap heeft een hogere resolutie het NWB (OSM segmenten zijn max 50 m. lang, NWB segmenten vaak langer). Met name bij langere en rechte NWB segmenten (weinig onderliggende punten in de polyline) levert dat problemen op bij het bepalen van de nearest neighbor. Om dat probleem te ondervangen zijn de NWB segmenten eerst kunstmatig opgeknipt in segmenten van max 50 m.

source('prepare_shape.r')
lengte = 25

#Maak NWB equidistant
nwb_select_eq<- nwb_select
x = pblapply( c(1:length(nwb_select@lines)), function(i){
  as.data.frame(spacing(pad = nwb_select_eq@lines[[i]]@Lines[[1]]@coords  ,lengte= lengte))
})


for(i in 1:length(nwb_select@lines)){
  colnames(x[[i]]) = c('x','y')
  nwb_select_eq@lines[[i]]@Lines[[1]]@coords = as.matrix(x[[i]])
}



#Maak OSM equidistant
basemap_select_eq<- basemap_select
x = pblapply( c(1:length(basemap_select@lines)), function(i){
  spacing(pad = basemap_select_eq@lines[[i]]@Lines[[1]]@coords  ,lengte= lengte)
})

for(i in 1:length(basemap_select_eq@lines)){
   colnames(x[[i]]) = c('x','y')
  basemap_select_eq@lines[[i]]@Lines[[1]]@coords = as.matrix(x[[i]])
}

MATCH lines door middel van mean distance

We berekenen per OSM line en per NWB line de afstand van alle punten op de NWB line tot alle punten of de OSM line. Vervolgens nemen we voor ieder OSM punt de minimale afstand tot de punten op de NWB line. Van deze afstanden nemen we het maximum. Dit noemen we de half-hausdorf afstand tussen de twee lines. Voor idere OSM line matchen we de NWB line met de kleinste half-hausdorf afstand.

basemap_select_eq$segmentID<- as.integer(as.character(basemap_select_eq$segmentID))
source('half_hausdorf.r')
OSM = basemap_select_eq
NWB = nwb_select_eq

distance_lijst_OSM = pblapply(c(1:length(OSM@lines)), function(i){
  
  hausdorf_distances_to_NWB_lines =   lapply(c(1:length(NWB@lines)),function(j){
    mean_dist(OSM@lines[[i]]@Lines[[1]]@coords, NWB@lines[[j]]@Lines[[1]]@coords  )
  })
  
  
  minimum_distance_osm = min(unlist( hausdorf_distances_to_NWB_lines))
  label = which.min( unlist(hausdorf_distances_to_NWB_lines) )
  
  return(c(OSM$segmentID[i],as.numeric(as.character(NWB$WVK_ID[label])), minimum_distance_osm))
})

distance_lijst_NWB = pblapply(c(1:length(NWB@lines)), function(i){
    hausdorf_distances_to_OSM_lines =   lapply(c(1:length(OSM@lines)),function(j){
    mean_dist(NWB@lines[[i]]@Lines[[1]]@coords, OSM@lines[[j]]@Lines[[1]]@coords  )
  })
  
  minimum_distance_nwb = min(unlist( hausdorf_distances_to_NWB_lines))
  label = which.min( unlist(hausdorf_distances_to_NWB_lines) )
  
  return(c(NWB$WVK_ID[i],as.numeric(as.character(OSM$segmentID[label])), minimum_distance_nwb))
})

#create df with nearest neighbors
distance_matrix_OSM = as.data.frame(do.call(rbind, distance_lijst_OSM))[,c(1:3)]
colnames(distance_matrix_OSM) = c('OSM_id', 'NWB_id', 'Half_Hausdorfdistance')

#create df with nearest neighbors
distance_matrix_NWB = as.data.frame(do.call(rbind, distance_lijst_NWB))[,c(1:3)]
colnames(distance_matrix_NWB) = c('NWB_id', 'OSM_id', 'Half_Hausdorfdistance')

Leaflet om verschillen inzichtelijk te maken

distance_matrix$ge50<- ifelse(distance_matrix$Half_Hausdorfdistance >=50, TRUE,FALSE) #hh distance greater than or equal to 50 m
#merge
basemap_select$nn_nwb_half<- distance_matrix$NWB_id[match(basemap_select$segmentID,distance_matrix$OSM_id)]
basemap_select$ge50<- distance_matrix$ge50[match(basemap_select$segmentID,distance_matrix$OSM_id)]
basemap_select$hh_dist<- distance_matrix$Half_Hausdorfdistance[match(basemap_select$segmentID,distance_matrix$OSM_id)]
nwb_select$is_nn50<- ifelse(nwb_select$WVK_ID %in% basemap_select$nn_nwb_half[basemap_select$hh_dist<50],TRUE,FALSE )
##back to wgs for plotting
wgs<- "+proj=longlat +ellps=WGS84 +datum=WGS84 +towgs84=0,0,0"
basemap_select_wgs<- spTransform(basemap_select,wgs)
nwb_select_wgs<- spTransform(nwb_select,wgs)
basemap_select_wgs<- basemap_select_wgs[order(basemap_select_wgs$nn_nwb_half),]
nwb_select_wgs<- nwb_select_wgs[order(nwb_select_wgs$WVK_ID),]
#export for shiny
#save(basemap_select_wgs,file="db/basemap_select_wgs.RData")
#save(nwb_select_wgs,file="db/nwb_select_wgs.RData")
#save(distance_matrix,file="db/dist_matrix.RData")
factpal <- colorFactor(c("green","black"), c(TRUE,FALSE))
factpal_nwb <- colorFactor(c("red","blue"), c(TRUE,FALSE))
##leaflet
leaflet() %>% addProviderTiles(providers$CartoDB)  %>% 
  addPolylines(data=nwb_select_wgs,opacity=0.5,col=~factpal_nwb(is_nn50),
               popup=~paste("WVK_ID: ",WVK_ID),group="NWB",highlightOptions=highlightOptions(fillOpacity = 1,
                              bringToFront = TRUE) ) %>% 
  addPolylines(data=basemap_select_wgs,weight = 5,opacity=0.5,col=~factpal(ge50),group="OSM",
               popup= ~paste("SegmentID:",segmentID, "<br>",
                             "nn_nwb: ",nn_nwb_half, "<br>",
                             "half_hausdorff: ", hh_dist),highlightOptions=highlightOptions(fillOpacity = 1,
                              bringToFront = TRUE)) %>%
  # Layers control
  addLayersControl(
    overlayGroups = c("NWB", "OSM"),
    options = layersControlOptions(collapsed = FALSE)) %>%
    addLegend("bottomright", colors = c("chartreuse","black","blue","red"), labels = c("Wel in OSM, ook in NWB","Wel in OSM, niet NWB",
                                                                                  "Wel in NWB, ook in OSM","Wel in NWB, niet in OSM"),
    title = "Legend",
    opacity = 0.7)

NA

Juncties van OSM en NWB vergelijken

Vind de juncties en bepaal voor iedere junctie in OSM het dichtsbijzijnde junctie in NWB en andersom

#VUL HIER NIET DE EQUIDISTANTE SHAPE IN MAAR DE ORGINELE SHAPES!
source('vind_juncties.r')
OSM_juncties = vind_juncties(basemap_select)
NWB_juncties = vind_juncties(nwb_select)
dichtst_bijzijnde_NWB_junctie =  pblapply(c(1:nrow(OSM_juncties)), function(i){
 x =  sqrt ( (NWB_juncties[,1] - OSM_juncties[i,1])^2   +   (NWB_juncties[,2] - OSM_juncties[i,2])^2 )
 x = NWB_juncties[x == min(x),] 
 return(x[1,])
 
})

   |                                                  | 0 % ~calculating  
   |+                                                 | 1 % ~04s          
   |+                                                 | 2 % ~04s          
   |++                                                | 3 % ~04s          
   |++                                                | 4 % ~04s          
   |+++                                               | 5 % ~04s          
   |+++                                               | 6 % ~04s          
   |++++                                              | 7 % ~03s          
   |++++                                              | 8 % ~03s          
   |+++++                                             | 9 % ~03s          
   |+++++                                             | 10% ~03s          
   |++++++                                            | 11% ~03s          
   |++++++                                            | 12% ~07s          
   |+++++++                                           | 13% ~06s          
   |+++++++                                           | 14% ~06s          
   |++++++++                                          | 15% ~06s          
   |++++++++                                          | 16% ~05s          
   |+++++++++                                         | 17% ~05s          
   |+++++++++                                         | 18% ~05s          
   |++++++++++                                        | 19% ~05s          
   |++++++++++                                        | 20% ~05s          
   |+++++++++++                                       | 21% ~05s          
   |+++++++++++                                       | 22% ~04s          
   |++++++++++++                                      | 23% ~04s          
   |++++++++++++                                      | 24% ~04s          
   |+++++++++++++                                     | 25% ~04s          
   |+++++++++++++                                     | 26% ~04s          
   |++++++++++++++                                    | 27% ~04s          
   |++++++++++++++                                    | 28% ~04s          
   |+++++++++++++++                                   | 29% ~04s          
   |+++++++++++++++                                   | 30% ~04s          
   |++++++++++++++++                                  | 31% ~04s          
   |++++++++++++++++                                  | 32% ~04s          
   |+++++++++++++++++                                 | 33% ~04s          
   |+++++++++++++++++                                | 34% ~04s          
   |++++++++++++++++++                                | 35% ~04s          
   |++++++++++++++++++                                | 36% ~04s          
   |+++++++++++++++++++                               | 37% ~04s          
   |+++++++++++++++++++                               | 38% ~04s          
   |++++++++++++++++++++                              | 39% ~03s          
   |++++++++++++++++++++                              | 40% ~03s          
   |+++++++++++++++++++++                             | 41% ~03s          
   |+++++++++++++++++++++                             | 42% ~03s          
   |++++++++++++++++++++++                            | 43% ~03s          
   |++++++++++++++++++++++                            | 44% ~03s          
   |+++++++++++++++++++++++                           | 45% ~03s          
   |+++++++++++++++++++++++                           | 46% ~03s          
   |++++++++++++++++++++++++                          | 47% ~03s          
   |++++++++++++++++++++++++                          | 48% ~03s          
   |+++++++++++++++++++++++++                         | 49% ~03s          
   |+++++++++++++++++++++++++                         | 50% ~03s          
   |++++++++++++++++++++++++++                        | 51% ~03s          
   |++++++++++++++++++++++++++                        | 52% ~03s          
   |+++++++++++++++++++++++++++                       | 53% ~03s          
   |+++++++++++++++++++++++++++                       | 54% ~03s          
   |++++++++++++++++++++++++++++                      | 55% ~03s          
   |++++++++++++++++++++++++++++                     | 56% ~03s          
   |+++++++++++++++++++++++++++++                     | 57% ~02s          
   |+++++++++++++++++++++++++++++                     | 58% ~02s          
   |++++++++++++++++++++++++++++++                    | 59% ~02s          
   |++++++++++++++++++++++++++++++                    | 60% ~02s          
   |+++++++++++++++++++++++++++++++                   | 61% ~02s          
   |+++++++++++++++++++++++++++++++                   | 62% ~02s          
   |++++++++++++++++++++++++++++++++                  | 63% ~02s          
   |++++++++++++++++++++++++++++++++                  | 64% ~02s          
   |+++++++++++++++++++++++++++++++++                 | 65% ~02s          
   |+++++++++++++++++++++++++++++++++                 | 66% ~02s          
   |++++++++++++++++++++++++++++++++++                | 67% ~02s          
   |++++++++++++++++++++++++++++++++++               | 68% ~02s          
   |+++++++++++++++++++++++++++++++++++               | 69% ~02s          
   |+++++++++++++++++++++++++++++++++++               | 70% ~02s          
   |++++++++++++++++++++++++++++++++++++              | 71% ~02s          
   |++++++++++++++++++++++++++++++++++++              | 72% ~02s          
   |+++++++++++++++++++++++++++++++++++++             | 73% ~02s          
   |+++++++++++++++++++++++++++++++++++++             | 74% ~01s          
   |++++++++++++++++++++++++++++++++++++++            | 75% ~01s          
   |++++++++++++++++++++++++++++++++++++++            | 76% ~01s          
   |+++++++++++++++++++++++++++++++++++++++           | 77% ~01s          
   |+++++++++++++++++++++++++++++++++++++++          | 78% ~01s          
   |++++++++++++++++++++++++++++++++++++++++          | 79% ~01s          
   |++++++++++++++++++++++++++++++++++++++++         | 80% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++         | 81% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++         | 82% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++        | 83% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++        | 84% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++++++    | 90% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++++++   | 92% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed = 06s
dichtst_bijzijnde_NWB_junctie =  do.call(rbind, dichtst_bijzijnde_NWB_junctie)
OSM_juncties = cbind(OSM_juncties, dichtst_bijzijnde_NWB_junctie )
colnames(OSM_juncties) = c('x_OSM', 'y_OSM', 'x_NWB', 'y_NWB')
dichtst_bijzijnde_OSM_junctie =  pblapply(c(1:nrow(NWB_juncties)), function(i){
 x =  sqrt ( (OSM_juncties[,1] - NWB_juncties[i,1])^2   +   (OSM_juncties[,2] - NWB_juncties[i,2])^2 )
 x = OSM_juncties[x == min(x),] 
 
 return(x[1,])
 
})

   |                                                  | 0 % ~calculating  
   |+                                                 | 1 % ~02s          
   |+                                                 | 2 % ~02s          
   |++                                                | 3 % ~02s          
   |++                                                | 4 % ~02s          
   |+++                                               | 5 % ~02s          
   |+++                                               | 6 % ~02s          
   |++++                                              | 7 % ~02s          
   |++++                                              | 8 % ~02s          
   |+++++                                             | 9 % ~02s          
   |+++++                                             | 10% ~02s          
   |++++++                                            | 11% ~02s          
   |++++++                                            | 12% ~02s          
   |+++++++                                           | 13% ~02s          
   |+++++++                                           | 14% ~02s          
   |++++++++                                          | 15% ~02s          
   |++++++++                                          | 16% ~04s          
   |+++++++++                                         | 17% ~03s          
   |+++++++++                                         | 18% ~03s          
   |++++++++++                                        | 19% ~03s          
   |++++++++++                                        | 20% ~03s          
   |+++++++++++                                       | 21% ~03s          
   |+++++++++++                                       | 22% ~03s          
   |++++++++++++                                      | 23% ~03s          
   |++++++++++++                                      | 24% ~03s          
   |+++++++++++++                                     | 25% ~03s          
   |+++++++++++++                                     | 26% ~03s          
   |++++++++++++++                                    | 27% ~02s          
   |++++++++++++++                                    | 28% ~02s          
   |+++++++++++++++                                   | 29% ~02s          
   |+++++++++++++++                                   | 30% ~02s          
   |++++++++++++++++                                  | 31% ~02s          
   |++++++++++++++++                                  | 32% ~03s          
   |+++++++++++++++++                                 | 33% ~03s          
   |+++++++++++++++++                                | 34% ~03s          
   |++++++++++++++++++                                | 35% ~03s          
   |++++++++++++++++++                                | 36% ~03s          
   |+++++++++++++++++++                               | 37% ~02s          
   |+++++++++++++++++++                               | 38% ~02s          
   |++++++++++++++++++++                              | 39% ~02s          
   |++++++++++++++++++++                              | 40% ~02s          
   |+++++++++++++++++++++                             | 41% ~02s          
   |+++++++++++++++++++++                             | 42% ~02s          
   |++++++++++++++++++++++                            | 43% ~02s          
   |++++++++++++++++++++++                            | 44% ~02s          
   |+++++++++++++++++++++++                           | 45% ~02s          
   |+++++++++++++++++++++++                           | 46% ~02s          
   |++++++++++++++++++++++++                          | 47% ~02s          
   |++++++++++++++++++++++++                          | 48% ~02s          
   |+++++++++++++++++++++++++                         | 49% ~02s          
   |+++++++++++++++++++++++++                         | 50% ~02s          
   |++++++++++++++++++++++++++                        | 51% ~02s          
   |++++++++++++++++++++++++++                        | 52% ~02s          
   |+++++++++++++++++++++++++++                       | 53% ~02s          
   |+++++++++++++++++++++++++++                       | 54% ~02s          
   |++++++++++++++++++++++++++++                      | 55% ~02s          
   |++++++++++++++++++++++++++++                     | 56% ~02s          
   |+++++++++++++++++++++++++++++                     | 57% ~02s          
   |+++++++++++++++++++++++++++++                     | 58% ~02s          
   |++++++++++++++++++++++++++++++                    | 59% ~02s          
   |++++++++++++++++++++++++++++++                    | 60% ~01s          
   |+++++++++++++++++++++++++++++++                   | 61% ~01s          
   |+++++++++++++++++++++++++++++++                   | 62% ~01s          
   |++++++++++++++++++++++++++++++++                  | 63% ~02s          
   |++++++++++++++++++++++++++++++++                  | 64% ~01s          
   |+++++++++++++++++++++++++++++++++                 | 65% ~01s          
   |+++++++++++++++++++++++++++++++++                 | 66% ~01s          
   |++++++++++++++++++++++++++++++++++                | 67% ~01s          
   |++++++++++++++++++++++++++++++++++               | 68% ~01s          
   |+++++++++++++++++++++++++++++++++++               | 69% ~01s          
   |+++++++++++++++++++++++++++++++++++               | 70% ~01s          
   |++++++++++++++++++++++++++++++++++++              | 71% ~01s          
   |++++++++++++++++++++++++++++++++++++              | 72% ~01s          
   |+++++++++++++++++++++++++++++++++++++             | 73% ~01s          
   |+++++++++++++++++++++++++++++++++++++             | 74% ~01s          
   |++++++++++++++++++++++++++++++++++++++            | 75% ~01s          
   |++++++++++++++++++++++++++++++++++++++            | 76% ~01s          
   |+++++++++++++++++++++++++++++++++++++++           | 77% ~01s          
   |+++++++++++++++++++++++++++++++++++++++          | 78% ~01s          
   |++++++++++++++++++++++++++++++++++++++++          | 79% ~01s          
   |++++++++++++++++++++++++++++++++++++++++         | 80% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++         | 81% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++         | 82% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++        | 83% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++        | 84% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++++       | 85% ~01s          
   |+++++++++++++++++++++++++++++++++++++++++++       | 86% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++++      | 87% ~01s          
   |++++++++++++++++++++++++++++++++++++++++++++      | 88% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++     | 89% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++    | 90% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++    | 91% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++   | 92% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++   | 93% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++   | 94% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++  | 95% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++  | 96% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++++ | 97% ~00s          
   |+++++++++++++++++++++++++++++++++++++++++++++++++ | 98% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++++| 99% ~00s          
   |++++++++++++++++++++++++++++++++++++++++++++++++++| 100% elapsed = 04s
dichtst_bijzijnde_OSM_junctie =  do.call(rbind, dichtst_bijzijnde_OSM_junctie)
NWB_juncties = cbind(dichtst_bijzijnde_NWB_junctie , OSM_juncties )
colnames(NWB_juncties) = c('x_NWB', 'y_NWB', 'x_OSM', 'y_OSM')

Vind afwijkende vormen doormiddeln van de hausdorf distance

Vind voor alle punten op een NWB segment de dichtsbijzijnde punten van OSM. Kijk of het maximum en het gemiddelde niet tever afwijken.

#GEBRUIK NU WEL EQUIDISTANTE SHAPES

#zet alle punten van OSM in een dataframe

points_OSM = pblapply(c(1:length(OSM@lines)), function(i){
  as.data.frame(OSM@lines[[i]]@Lines[[1]]@coords)
})
points_OSM = rbindlist(points_OSM)
points_OSM = points_OSM[!duplicated(points_OSM),]

#zet alle punten van het NWB in een dataframe
points_NWB = pblapply(c(1:length(NWB@lines)), function(i){
  as.data.frame(NWB@lines[[i]]@Lines[[1]]@coords)
})
points_NWB = rbindlist(points_NWB)
points_NWB = points_NWB[!duplicated(points_NWB),]



#bereken de nearest neighbour afstand voor ieder punt in het nwb ten opzichten van de punten in het OSM

NWB_to_OSM_points = pblapply(c(1:nrow(points_NWB)) , function(i){
  

    distances = sqrt( ( points_OSM[,1] - as.numeric(points_NWB[i,1])   )^2  +  (  points_OSM[,2] - as.numeric(points_NWB[i,2])   )^2 )
    
    
    
  
  return( min(distances))
})

drempel = 30

locaties_fouten = points_NWB[unlist(NWB_to_OSM_points) > drempel  ,] 

Floating car data samenvoegen

Dit stuk code leest alle tabellen van de floatin car data en maakt er een tabel van met 4 kolommen. Het wegsegment ID, de gemiddeld gereden snelheid, het aantal tabellen waarin het segement voorkomt en de cummulatieve intensiteit. Deze tabel word gemaakt voor 6-19 en 19-6 om rekening te houden met wisseling in maximum snelheid.

tabel_overdag = merge_tables(dir = dir,uur1 = uur1, uur2 = uur2)

vind doodlopende wegen

Er komen soms kleine onterechte aftakkingen voor in het NWB om die op te kunnen sporen vergelijken we expleciet de doodlopende wegen van het NWB met het OSM.



  rand = data.frame('x'= -1, 'y' = -1)

 for(i in 1:length(nwb_select@lines)){

    nieuw = nwb_select@lines[[i]]@Lines[[1]]@coords
    colnames(nieuw) = c('x','y')
    rand_nieuw = rbind(nieuw[1,] ,nieuw[nrow(nieuw),])
    
    rand = rbind(rand, rand_nieuw)
  
 }
rand = rand[-1,]

doodlopend_nwb = rand[!duplicated(rand),]


  rand = data.frame('x'= -1, 'y' = -1)

 for(i in 1:length(basemap_select@lines)){

    nieuw = basemap_select@lines[[i]]@Lines[[1]]@coords
    colnames(nieuw) = c('x','y')
    rand_nieuw = rbind(nieuw[1,] ,nieuw[nrow(nieuw),])
    
    rand = rbind(rand, rand_nieuw)
  
 }
rand = rand[-1,]

doodlopend_osm = rand[!duplicated(rand),]
LS0tCnRpdGxlOiAiTldCX0ZDRCBwcm9qZWN0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpQcm9qZWN0IGluIG9wZHJhY2h0IHZhbiBOV0IgcHJvamVjdHRlYW0sIHVpdGdldm9lcmQgZG9vciBSV1MgRGF0YWxhYi4KClRlYW06ICAKW01hcnRpam4gS29vbGVdKG1hcnRpam4ua29vbGVAcndzLm5sKSAtIERhdGEgU2NpZW50aXN0ICAKW0RhYW4gdmFuIGRlciBNYWFzXShkYWFuLnZhbmRlci5tYWFzQHJ3cy5ubCkgLSBEYXRhIFNjaWVudGlzdCAgCltKYW4gUXVpc3RdKGphbi5xdWlzdEByd3MubmwpIC0gRGF0YSBTY2llbnRpc3QgIApbU3RldmVuIHZhbiBHZWxkZXJdKHN0ZXZlbi52YW4uZ2VsZGVyQHJ3cy5ubCkgLSBQcm9kdWN0IG1hbmFnZXIgIApbVmlrYXNoIFJhbWJhcmFuXSh2aWthc2gucmFtYmFyYW5AcndzLm5sKSAtIFByb2R1Y3QgT3duZXIgIAoKCiNEYXRhIGxhZGVuIGVuIHByZXByb2Nlc3NpbmcKT25kZXJzdGFhbmRlIGNvZGUgaW1wb3J0ZWVydCBhbGxlIGJlbm9kaWdkZSBsaWJyYXJpZXMgZW4gZnVuY3RpZXMgZW4gbGFhZHQgdmVydm9sZ2VucyBkZSBnZWJydWlrdGUgZGF0YS4gRXIgaXMgZWVuIHVpdHNuZWRlIGdlbWFha3QgdmFuIGhldCBOV0IgV2VndmFra2VuIGJlc3RhbmQgdmFuIDAxLTA2LTIwMTcgcm9uZG9tIEdvdWRhLiBWZXJ2b2xnZW5zIGlzIGVlbiB6ZWxmZGUgdWl0c25lZGUgZ2VtYWFrdCB2b29yIGRlIEJhc2VtYXAgZGllIHZlcmtyZWdlbiBpcyB2aWEgQmVNb2JpbGUgKGdlYmFzZWVyZCBvcCBPcGVuIFN0cmVldCBNYXAsIE9TTSkuIERlIHVpdHNuZWRlIGlzIGluIGVlcnN0ZSBpbnN0YW50aWUgZ2VtYWFrdCBvbSBkZSByZWtlbnRpamQga29ydCB0ZSBob3VkZW4gdGlqZGVucyBvbnR3aWtrZWxlbi90ZXN0ZW4uIERhdCBnZWJldXJ0IGluIGhldCBzY3JpcHQgcmVhZF9mY2QuUi4gTGF0ZXIga3VubmVuIGRlemVsZmRlIHNjcmlwdHMgZ2VicnVpa3Qgd29yZGVuIHZvb3Igb20gb3ZlciBoZWVsIE5lZGVybGFuZCB2ZXJzY2hpbGxlbiB0ZSBkZXRlY3RlcmVuLgoKYGBge3IsIGVjaG89RixjYWNoZT1ULGV2YWw9Rn0Kc291cmNlKCdsaWIucicpCmxvYWQoImRiL2Jhc2VtYXBfc2VsZWN0LlJEYXRhIikKbG9hZCgiZGIvbndiX3NlbGVjdDIuUkRhdGEiKQpgYGAKCk9tIGhldCBOV0IgYmVzdGFuZCB0ZSBrdW5uZW4gdmVyZ2VsaWprZW4genVsbGVuIGRlemUgb3AgZWxrYWFyIGdlbWFwdCBtb2V0ZW4gd29yZGVuLiBIaWVydm9vciBpcyB2b29yIGllZGVyIGllZGVyIGxpam5zZWdtZW50IHVpdCBkZSBPU00gYmFzZW1hcCBnZXpvY2h0IG5hYXIgZWVuICduZWFyZXN0IG5laWdoYm9yJyBpbiBoZXQgTldCLiBNZXQgYmVodWxwIHZhbiBkZSBhZnN0YW5kIHRvdCBkZSBuZWFyZXN0IG5laWdoYm9yIGt1bm5lbiBhZndpamtpbmdlbiB3b3JkZW4gZ2VkZXRlY3RlZXJkLiBWb29yYmVlbGQ6IE9iamVjdGVuIGluIGRlIE9TTSBiYXNlbWFwIGRpZSBnZWVuIG5lYXJlc3QgbmVpZ2hib3IgaW4gaGV0IE5XQiBoZWJiZW4gYmlubmVuIGVlbiBiZXBhYWxkZSBtYXJnZSBrdW5uZW4gZHVpZGVuIG9wIG1pc3NlbmRlL29uanVpc3RlIGluZm9ybWF0aWUgaW4gaGV0IE5XQi4gQW5kZXJzb20gKE5XQiBvYmplY3Qgem9uZGVyIE9TTSBuZWFyZXN0IG5laWdoYm9yKSBkdWlkdCBvcCBlZW4gd2VnIGRpZSB3ZWwgaW4gTldCIGJlc3RhYXQsIG1hYXIgbmlldCBpbiBkZSBPU00gYmFzZW1hcC4gT20gZGUgYWZzdGFuZCB0ZSBiZXBhbGVuIHR1c3NlbiBlZW4gb2JqZWN0IGluIGRlIE9TTSBiYXNlbWFwIGVuIGVlbiBvYmplY3QgaW4gTldCLCBpcyBnZWJydWlrIGdlbWFha3QgdmFuIGVlbiBhZmdlbGVpZGUgdmFuIGRlIFtIYXVzZG9yZmYgZGlzdGFuY2VdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0hhdXNkb3JmZl9kaXN0YW5jZSkuIEhpZXJ2b29yIGlzIGVlcnN0IG5vZyBlbmlnZSBiZXdlcmtpbmcgZ2VkYWFuLgoKCmBgYHtyLGVjaG89VCxldmFsPUZ9CiNFZXJzdCB3b3JkZW4gYmVpZGUgc2hhcGVzIG9tZ2V6ZXQgbmFhciBSRCBjb29yZGluYXRlbiwgdC5iLnYuIGVlbmhlaWQgbWV0ZXIKcmQ8LSAiK3Byb2o9c3RlcmVhICtsYXRfMD01Mi4xNTYxNjA1NTU1NTU1NSArbG9uXzA9NS4zODc2Mzg4ODg4ODg4OSAraz0wLjk5OTkwOCAreF8wPTE1NTAwMCAreV8wPTQ2MzAwMCArZWxscHM9YmVzc2VsICt1bml0cz1tICt0b3dnczg0PTU2NS4yMzY5LDUwLjAwODcsNDY1LjY1OCwtMC40MDY4NTczMzAzMjIzOTgsMC4zNTA3MzI2NzY1NDI1NjMsLTEuODcwMzQ3MzgzNjA2OCw0LjA4MTIgK25vX2RlZnMiCgpud2Jfc2VsZWN0PC0gc3BUcmFuc2Zvcm0obndiX3NlbGVjdCxyZCkKYmFzZW1hcF9zZWxlY3Q8LSBzcFRyYW5zZm9ybShiYXNlbWFwX3NlbGVjdCxyZCkKCmBgYAoKIyNFcXVpZGlzdGFudApCZWlkZSBiZXN0YW5kZW4gYmVzdGFhbiB1aXQgUG9seWxpbmUgc2hhcGVzLCBtYWFyIGRlIE9TTSBiYXNlbWFwIGhlZWZ0IGVlbiBob2dlcmUgcmVzb2x1dGllIGhldCBOV0IgKE9TTSBzZWdtZW50ZW4gemlqbiBtYXggNTAgbS4gbGFuZywgTldCIHNlZ21lbnRlbiB2YWFrIGxhbmdlcikuIE1ldCBuYW1lIGJpaiBsYW5nZXJlIGVuIHJlY2h0ZSBOV0Igc2VnbWVudGVuICh3ZWluaWcgb25kZXJsaWdnZW5kZSBwdW50ZW4gaW4gZGUgcG9seWxpbmUpIGxldmVydCBkYXQgcHJvYmxlbWVuIG9wIGJpaiBoZXQgYmVwYWxlbiB2YW4gZGUgbmVhcmVzdCBuZWlnaGJvci4gT20gZGF0IHByb2JsZWVtIHRlIG9uZGVydmFuZ2VuIHppam4gZGUgTldCIHNlZ21lbnRlbiBlZXJzdCBrdW5zdG1hdGlnIG9wZ2VrbmlwdCBpbiBzZWdtZW50ZW4gdmFuIG1heCA1MCBtLgoKYGBge3IsZWNobz1ULGV2YWw9Rn0Kc291cmNlKCdwcmVwYXJlX3NoYXBlLnInKQpsZW5ndGUgPSAyNQoKI01hYWsgTldCIGVxdWlkaXN0YW50Cm53Yl9zZWxlY3RfZXE8LSBud2Jfc2VsZWN0CnggPSBwYmxhcHBseSggYygxOmxlbmd0aChud2Jfc2VsZWN0QGxpbmVzKSksIGZ1bmN0aW9uKGkpewogIGFzLmRhdGEuZnJhbWUoc3BhY2luZyhwYWQgPSBud2Jfc2VsZWN0X2VxQGxpbmVzW1tpXV1ATGluZXNbWzFdXUBjb29yZHMgICxsZW5ndGU9IGxlbmd0ZSkpCn0pCgoKZm9yKGkgaW4gMTpsZW5ndGgobndiX3NlbGVjdEBsaW5lcykpewogIGNvbG5hbWVzKHhbW2ldXSkgPSBjKCd4JywneScpCiAgbndiX3NlbGVjdF9lcUBsaW5lc1tbaV1dQExpbmVzW1sxXV1AY29vcmRzID0gYXMubWF0cml4KHhbW2ldXSkKfQoKCgojTWFhayBPU00gZXF1aWRpc3RhbnQKYmFzZW1hcF9zZWxlY3RfZXE8LSBiYXNlbWFwX3NlbGVjdAp4ID0gcGJsYXBwbHkoIGMoMTpsZW5ndGgoYmFzZW1hcF9zZWxlY3RAbGluZXMpKSwgZnVuY3Rpb24oaSl7CiAgc3BhY2luZyhwYWQgPSBiYXNlbWFwX3NlbGVjdF9lcUBsaW5lc1tbaV1dQExpbmVzW1sxXV1AY29vcmRzICAsbGVuZ3RlPSBsZW5ndGUpCn0pCgpmb3IoaSBpbiAxOmxlbmd0aChiYXNlbWFwX3NlbGVjdF9lcUBsaW5lcykpewogICBjb2xuYW1lcyh4W1tpXV0pID0gYygneCcsJ3knKQogIGJhc2VtYXBfc2VsZWN0X2VxQGxpbmVzW1tpXV1ATGluZXNbWzFdXUBjb29yZHMgPSBhcy5tYXRyaXgoeFtbaV1dKQp9CgoKCmBgYAoKIyNNQVRDSCBsaW5lcyBkb29yIG1pZGRlbCB2YW4gbWVhbiBkaXN0YW5jZQpXZSBiZXJla2VuZW4gcGVyIE9TTSBsaW5lIGVuIHBlciBOV0IgbGluZSBkZSBhZnN0YW5kIHZhbiBhbGxlIHB1bnRlbiBvcCBkZSBOV0IgbGluZSB0b3QgYWxsZSBwdW50ZW4gb2YgZGUgT1NNIGxpbmUuIFZlcnZvbGdlbnMgbmVtZW4gd2Ugdm9vciBpZWRlciBPU00gcHVudCBkZSBtaW5pbWFsZSBhZnN0YW5kIHRvdCBkZSBwdW50ZW4gb3AgZGUgTldCIGxpbmUuIFZhbiBkZXplIGFmc3RhbmRlbiBuZW1lbiB3ZSBoZXQgbWF4aW11bS4gRGl0IG5vZW1lbiB3ZSBkZSBoYWxmLWhhdXNkb3JmIGFmc3RhbmQgdHVzc2VuIGRlIHR3ZWUgbGluZXMuIFZvb3IgaWRlcmUgT1NNIGxpbmUgbWF0Y2hlbiB3ZSBkZSBOV0IgbGluZSBtZXQgZGUga2xlaW5zdGUgaGFsZi1oYXVzZG9yZiBhZnN0YW5kLgoKIAoKYGBge3IsZWNobz1ULGV2YWw9RixjYWNoZT1UfQoKYmFzZW1hcF9zZWxlY3RfZXEkc2VnbWVudElEPC0gYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIoYmFzZW1hcF9zZWxlY3RfZXEkc2VnbWVudElEKSkKc291cmNlKCdoYWxmX2hhdXNkb3JmLnInKQpPU00gPSBiYXNlbWFwX3NlbGVjdF9lcQpOV0IgPSBud2Jfc2VsZWN0X2VxCgpkaXN0YW5jZV9saWpzdF9PU00gPSBwYmxhcHBseShjKDE6bGVuZ3RoKE9TTUBsaW5lcykpLCBmdW5jdGlvbihpKXsKICAKICBoYXVzZG9yZl9kaXN0YW5jZXNfdG9fTldCX2xpbmVzID0gICBsYXBwbHkoYygxOmxlbmd0aChOV0JAbGluZXMpKSxmdW5jdGlvbihqKXsKICAgIG1lYW5fZGlzdChPU01AbGluZXNbW2ldXUBMaW5lc1tbMV1dQGNvb3JkcywgTldCQGxpbmVzW1tqXV1ATGluZXNbWzFdXUBjb29yZHMgICkKICB9KQogIAogIAogIG1pbmltdW1fZGlzdGFuY2Vfb3NtID0gbWluKHVubGlzdCggaGF1c2RvcmZfZGlzdGFuY2VzX3RvX05XQl9saW5lcykpCiAgbGFiZWwgPSB3aGljaC5taW4oIHVubGlzdChoYXVzZG9yZl9kaXN0YW5jZXNfdG9fTldCX2xpbmVzKSApCiAgCiAgcmV0dXJuKGMoT1NNJHNlZ21lbnRJRFtpXSxhcy5udW1lcmljKGFzLmNoYXJhY3RlcihOV0IkV1ZLX0lEW2xhYmVsXSkpLCBtaW5pbXVtX2Rpc3RhbmNlX29zbSkpCn0pCgpkaXN0YW5jZV9saWpzdF9OV0IgPSBwYmxhcHBseShjKDE6bGVuZ3RoKE5XQkBsaW5lcykpLCBmdW5jdGlvbihpKXsKICAgIGhhdXNkb3JmX2Rpc3RhbmNlc190b19PU01fbGluZXMgPSAgIGxhcHBseShjKDE6bGVuZ3RoKE9TTUBsaW5lcykpLGZ1bmN0aW9uKGopewogICAgbWVhbl9kaXN0KE5XQkBsaW5lc1tbaV1dQExpbmVzW1sxXV1AY29vcmRzLCBPU01AbGluZXNbW2pdXUBMaW5lc1tbMV1dQGNvb3JkcyAgKQogIH0pCiAgCiAgbWluaW11bV9kaXN0YW5jZV9ud2IgPSBtaW4odW5saXN0KCBoYXVzZG9yZl9kaXN0YW5jZXNfdG9fTldCX2xpbmVzKSkKICBsYWJlbCA9IHdoaWNoLm1pbiggdW5saXN0KGhhdXNkb3JmX2Rpc3RhbmNlc190b19OV0JfbGluZXMpICkKICAKICByZXR1cm4oYyhOV0IkV1ZLX0lEW2ldLGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKE9TTSRzZWdtZW50SURbbGFiZWxdKSksIG1pbmltdW1fZGlzdGFuY2VfbndiKSkKfSkKCiNjcmVhdGUgZGYgd2l0aCBuZWFyZXN0IG5laWdoYm9ycwpkaXN0YW5jZV9tYXRyaXhfT1NNID0gYXMuZGF0YS5mcmFtZShkby5jYWxsKHJiaW5kLCBkaXN0YW5jZV9saWpzdF9PU00pKVssYygxOjMpXQpjb2xuYW1lcyhkaXN0YW5jZV9tYXRyaXhfT1NNKSA9IGMoJ09TTV9pZCcsICdOV0JfaWQnLCAnSGFsZl9IYXVzZG9yZmRpc3RhbmNlJykKCiNjcmVhdGUgZGYgd2l0aCBuZWFyZXN0IG5laWdoYm9ycwpkaXN0YW5jZV9tYXRyaXhfTldCID0gYXMuZGF0YS5mcmFtZShkby5jYWxsKHJiaW5kLCBkaXN0YW5jZV9saWpzdF9OV0IpKVssYygxOjMpXQpjb2xuYW1lcyhkaXN0YW5jZV9tYXRyaXhfTldCKSA9IGMoJ05XQl9pZCcsICdPU01faWQnLCAnSGFsZl9IYXVzZG9yZmRpc3RhbmNlJykKCmBgYAoKIyNMZWFmbGV0IG9tIHZlcnNjaGlsbGVuIGluemljaHRlbGlqayB0ZSBtYWtlbgpgYGB7cn0KCgpkaXN0YW5jZV9tYXRyaXgkZ2U1MDwtIGlmZWxzZShkaXN0YW5jZV9tYXRyaXgkSGFsZl9IYXVzZG9yZmRpc3RhbmNlID49NTAsIFRSVUUsRkFMU0UpICNoaCBkaXN0YW5jZSBncmVhdGVyIHRoYW4gb3IgZXF1YWwgdG8gNTAgbQoKI21lcmdlCmJhc2VtYXBfc2VsZWN0JG5uX253Yl9oYWxmPC0gZGlzdGFuY2VfbWF0cml4JE5XQl9pZFttYXRjaChiYXNlbWFwX3NlbGVjdCRzZWdtZW50SUQsZGlzdGFuY2VfbWF0cml4JE9TTV9pZCldCmJhc2VtYXBfc2VsZWN0JGdlNTA8LSBkaXN0YW5jZV9tYXRyaXgkZ2U1MFttYXRjaChiYXNlbWFwX3NlbGVjdCRzZWdtZW50SUQsZGlzdGFuY2VfbWF0cml4JE9TTV9pZCldCmJhc2VtYXBfc2VsZWN0JGhoX2Rpc3Q8LSBkaXN0YW5jZV9tYXRyaXgkSGFsZl9IYXVzZG9yZmRpc3RhbmNlW21hdGNoKGJhc2VtYXBfc2VsZWN0JHNlZ21lbnRJRCxkaXN0YW5jZV9tYXRyaXgkT1NNX2lkKV0KCm53Yl9zZWxlY3QkaXNfbm41MDwtIGlmZWxzZShud2Jfc2VsZWN0JFdWS19JRCAlaW4lIGJhc2VtYXBfc2VsZWN0JG5uX253Yl9oYWxmW2Jhc2VtYXBfc2VsZWN0JGhoX2Rpc3Q8NTBdLFRSVUUsRkFMU0UgKQoKIyNiYWNrIHRvIHdncyBmb3IgcGxvdHRpbmcKd2dzPC0gIitwcm9qPWxvbmdsYXQgK2VsbHBzPVdHUzg0ICtkYXR1bT1XR1M4NCArdG93Z3M4ND0wLDAsMCIKCmJhc2VtYXBfc2VsZWN0X3dnczwtIHNwVHJhbnNmb3JtKGJhc2VtYXBfc2VsZWN0LHdncykKbndiX3NlbGVjdF93Z3M8LSBzcFRyYW5zZm9ybShud2Jfc2VsZWN0LHdncykKCmJhc2VtYXBfc2VsZWN0X3dnczwtIGJhc2VtYXBfc2VsZWN0X3dnc1tvcmRlcihiYXNlbWFwX3NlbGVjdF93Z3Mkbm5fbndiX2hhbGYpLF0KbndiX3NlbGVjdF93Z3M8LSBud2Jfc2VsZWN0X3dnc1tvcmRlcihud2Jfc2VsZWN0X3dncyRXVktfSUQpLF0KCgojZXhwb3J0IGZvciBzaGlueQojc2F2ZShiYXNlbWFwX3NlbGVjdF93Z3MsZmlsZT0iZGIvYmFzZW1hcF9zZWxlY3Rfd2dzLlJEYXRhIikKI3NhdmUobndiX3NlbGVjdF93Z3MsZmlsZT0iZGIvbndiX3NlbGVjdF93Z3MuUkRhdGEiKQojc2F2ZShkaXN0YW5jZV9tYXRyaXgsZmlsZT0iZGIvZGlzdF9tYXRyaXguUkRhdGEiKQoKZmFjdHBhbCA8LSBjb2xvckZhY3RvcihjKCJncmVlbiIsImJsYWNrIiksIGMoVFJVRSxGQUxTRSkpCmZhY3RwYWxfbndiIDwtIGNvbG9yRmFjdG9yKGMoInJlZCIsImJsdWUiKSwgYyhUUlVFLEZBTFNFKSkKCiMjbGVhZmxldApsZWFmbGV0KCkgJT4lIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIpICAlPiUgCiAgYWRkUG9seWxpbmVzKGRhdGE9bndiX3NlbGVjdF93Z3Msb3BhY2l0eT0wLjUsY29sPX5mYWN0cGFsX253Yihpc19ubjUwKSwKICAgICAgICAgICAgICAgcG9wdXA9fnBhc3RlKCJXVktfSUQ6ICIsV1ZLX0lEKSxncm91cD0iTldCIixoaWdobGlnaHRPcHRpb25zPWhpZ2hsaWdodE9wdGlvbnMoZmlsbE9wYWNpdHkgPSAxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSApICU+JSAKICBhZGRQb2x5bGluZXMoZGF0YT1iYXNlbWFwX3NlbGVjdF93Z3Msd2VpZ2h0ID0gNSxvcGFjaXR5PTAuNSxjb2w9fmZhY3RwYWwoZ2U1MCksZ3JvdXA9Ik9TTSIsCiAgICAgICAgICAgICAgIHBvcHVwPSB+cGFzdGUoIlNlZ21lbnRJRDoiLHNlZ21lbnRJRCwgIjxicj4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJubl9ud2I6ICIsbm5fbndiX2hhbGYsICI8YnI+IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaGFsZl9oYXVzZG9yZmY6ICIsIGhoX2Rpc3QpLGhpZ2hsaWdodE9wdGlvbnM9aGlnaGxpZ2h0T3B0aW9ucyhmaWxsT3BhY2l0eSA9IDEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyaW5nVG9Gcm9udCA9IFRSVUUpKSAlPiUKICAjIExheWVycyBjb250cm9sCiAgYWRkTGF5ZXJzQ29udHJvbCgKICAgIG92ZXJsYXlHcm91cHMgPSBjKCJOV0IiLCAiT1NNIiksCiAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpKSAlPiUKCiAgICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgY29sb3JzID0gYygiY2hhcnRyZXVzZSIsImJsYWNrIiwiYmx1ZSIsInJlZCIpLCBsYWJlbHMgPSBjKCJXZWwgaW4gT1NNLCBvb2sgaW4gTldCIiwiV2VsIGluIE9TTSwgbmlldCBOV0IiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIldlbCBpbiBOV0IsIG9vayBpbiBPU00iLCJXZWwgaW4gTldCLCBuaWV0IGluIE9TTSIpLAogICAgdGl0bGUgPSAiTGVnZW5kIiwKICAgIG9wYWNpdHkgPSAwLjcpCiAgCgpgYGAKCgoKIyNKdW5jdGllcyB2YW4gT1NNIGVuIE5XQiB2ZXJnZWxpamtlbgpWaW5kIGRlIGp1bmN0aWVzIGVuIGJlcGFhbCB2b29yIGllZGVyZSBqdW5jdGllIGluIE9TTSBoZXQgZGljaHRzYmlqemlqbmRlIGp1bmN0aWUgaW4gTldCIGVuIGFuZGVyc29tCgoKYGBge3J9CgojVlVMIEhJRVIgTklFVCBERSBFUVVJRElTVEFOVEUgU0hBUEUgSU4gTUFBUiBERSBPUkdJTkVMRSBTSEFQRVMhCnNvdXJjZSgndmluZF9qdW5jdGllcy5yJykKCgoKT1NNX2p1bmN0aWVzID0gdmluZF9qdW5jdGllcyhiYXNlbWFwX3NlbGVjdCkKTldCX2p1bmN0aWVzID0gdmluZF9qdW5jdGllcyhud2Jfc2VsZWN0KQoKZGljaHRzdF9iaWp6aWpuZGVfTldCX2p1bmN0aWUgPSAgcGJsYXBwbHkoYygxOm5yb3coT1NNX2p1bmN0aWVzKSksIGZ1bmN0aW9uKGkpewogeCA9ICBzcXJ0ICggKE5XQl9qdW5jdGllc1ssMV0gLSBPU01fanVuY3RpZXNbaSwxXSleMiAgICsgICAoTldCX2p1bmN0aWVzWywyXSAtIE9TTV9qdW5jdGllc1tpLDJdKV4yICkKIHggPSBOV0JfanVuY3RpZXNbeCA9PSBtaW4oeCksXSAKIHJldHVybih4WzEsXSkKIAp9KQoKZGljaHRzdF9iaWp6aWpuZGVfTldCX2p1bmN0aWUgPSAgZG8uY2FsbChyYmluZCwgZGljaHRzdF9iaWp6aWpuZGVfTldCX2p1bmN0aWUpCk9TTV9qdW5jdGllcyA9IGNiaW5kKE9TTV9qdW5jdGllcywgZGljaHRzdF9iaWp6aWpuZGVfTldCX2p1bmN0aWUgKQpjb2xuYW1lcyhPU01fanVuY3RpZXMpID0gYygneF9PU00nLCAneV9PU00nLCAneF9OV0InLCAneV9OV0InKQoKCmRpY2h0c3RfYmlqemlqbmRlX09TTV9qdW5jdGllID0gIHBibGFwcGx5KGMoMTpucm93KE5XQl9qdW5jdGllcykpLCBmdW5jdGlvbihpKXsKIHggPSAgc3FydCAoIChPU01fanVuY3RpZXNbLDFdIC0gTldCX2p1bmN0aWVzW2ksMV0pXjIgICArICAgKE9TTV9qdW5jdGllc1ssMl0gLSBOV0JfanVuY3RpZXNbaSwyXSleMiApCiB4ID0gT1NNX2p1bmN0aWVzW3ggPT0gbWluKHgpLF0gCiAKIHJldHVybih4WzEsXSkKIAp9KQoKZGljaHRzdF9iaWp6aWpuZGVfT1NNX2p1bmN0aWUgPSAgZG8uY2FsbChyYmluZCwgZGljaHRzdF9iaWp6aWpuZGVfT1NNX2p1bmN0aWUpCk5XQl9qdW5jdGllcyA9IGNiaW5kKGRpY2h0c3RfYmlqemlqbmRlX05XQl9qdW5jdGllICwgT1NNX2p1bmN0aWVzICkKY29sbmFtZXMoTldCX2p1bmN0aWVzKSA9IGMoJ3hfTldCJywgJ3lfTldCJywgJ3hfT1NNJywgJ3lfT1NNJykKCgpgYGAKCiMjVmluZCBhZndpamtlbmRlIHZvcm1lbiBkb29ybWlkZGVsbiB2YW4gZGUgaGF1c2RvcmYgZGlzdGFuY2UKVmluZCB2b29yIGFsbGUgcHVudGVuIG9wIGVlbiBOV0Igc2VnbWVudCBkZSBkaWNodHNiaWp6aWpuZGUgcHVudGVuIHZhbiBPU00uIEtpamsgb2YgaGV0IG1heGltdW0gZW4gaGV0IGdlbWlkZGVsZGUgbmlldCB0ZXZlciBhZndpamtlbi4KCgpgYGB7cixlY2hvPVQsZXZhbD1GLGNhY2hlPVR9CiNHRUJSVUlLIE5VIFdFTCBFUVVJRElTVEFOVEUgU0hBUEVTCgojemV0IGFsbGUgcHVudGVuIHZhbiBPU00gaW4gZWVuIGRhdGFmcmFtZQoKcG9pbnRzX09TTSA9IHBibGFwcGx5KGMoMTpsZW5ndGgoT1NNQGxpbmVzKSksIGZ1bmN0aW9uKGkpewogIGFzLmRhdGEuZnJhbWUoT1NNQGxpbmVzW1tpXV1ATGluZXNbWzFdXUBjb29yZHMpCn0pCnBvaW50c19PU00gPSByYmluZGxpc3QocG9pbnRzX09TTSkKcG9pbnRzX09TTSA9IHBvaW50c19PU01bIWR1cGxpY2F0ZWQocG9pbnRzX09TTSksXQoKI3pldCBhbGxlIHB1bnRlbiB2YW4gaGV0IE5XQiBpbiBlZW4gZGF0YWZyYW1lCnBvaW50c19OV0IgPSBwYmxhcHBseShjKDE6bGVuZ3RoKE5XQkBsaW5lcykpLCBmdW5jdGlvbihpKXsKICBhcy5kYXRhLmZyYW1lKE5XQkBsaW5lc1tbaV1dQExpbmVzW1sxXV1AY29vcmRzKQp9KQpwb2ludHNfTldCID0gcmJpbmRsaXN0KHBvaW50c19OV0IpCnBvaW50c19OV0IgPSBwb2ludHNfTldCWyFkdXBsaWNhdGVkKHBvaW50c19OV0IpLF0KCgoKI2JlcmVrZW4gZGUgbmVhcmVzdCBuZWlnaGJvdXIgYWZzdGFuZCB2b29yIGllZGVyIHB1bnQgaW4gaGV0IG53YiB0ZW4gb3B6aWNodGVuIHZhbiBkZSBwdW50ZW4gaW4gaGV0IE9TTQoKTldCX3RvX09TTV9wb2ludHMgPSBwYmxhcHBseShjKDE6bnJvdyhwb2ludHNfTldCKSkgLCBmdW5jdGlvbihpKXsKICAKCiAgICBkaXN0YW5jZXMgPSBzcXJ0KCAoIHBvaW50c19PU01bLDFdIC0gYXMubnVtZXJpYyhwb2ludHNfTldCW2ksMV0pICAgKV4yICArICAoICBwb2ludHNfT1NNWywyXSAtIGFzLm51bWVyaWMocG9pbnRzX05XQltpLDJdKSAgICleMiApCiAgICAKICAgIAogICAgCiAgCiAgcmV0dXJuKCBtaW4oZGlzdGFuY2VzKSkKfSkKCmRyZW1wZWwgPSAzMAoKbG9jYXRpZXNfZm91dGVuID0gcG9pbnRzX05XQlt1bmxpc3QoTldCX3RvX09TTV9wb2ludHMpID4gZHJlbXBlbCAgLF0gCgpgYGAKCgoKIyNGbG9hdGluZyBjYXIgZGF0YSBzYW1lbnZvZWdlbgpEaXQgc3R1ayBjb2RlIGxlZXN0IGFsbGUgdGFiZWxsZW4gdmFuIGRlIGZsb2F0aW4gY2FyIGRhdGEgZW4gbWFha3QgZXIgZWVuIHRhYmVsIHZhbiBtZXQgNCBrb2xvbW1lbi4gSGV0IHdlZ3NlZ21lbnQgSUQsIGRlIGdlbWlkZGVsZCBnZXJlZGVuIHNuZWxoZWlkLCBoZXQgYWFudGFsIHRhYmVsbGVuIHdhYXJpbiBoZXQgc2VnZW1lbnQgdm9vcmtvbXQgZW4gZGUgY3VtbXVsYXRpZXZlIGludGVuc2l0ZWl0LiBEZXplIHRhYmVsIHdvcmQgZ2VtYWFrdCB2b29yIDYtMTkgZW4gMTktNiBvbSByZWtlbmluZyB0ZSBob3VkZW4gbWV0IHdpc3NlbGluZyBpbiBtYXhpbXVtIHNuZWxoZWlkLgoKYGBge3J9CmxpYnJhcnkoZm9yZWlnbikKYmFzZV9mdWxsPXJlYWQuZGJmKCJkYi9iYXNlbWFwcy8xMzM1NC1zaGFwZXMvc2VnbWVudHMuZGJmIikKCnNvdXJjZSgnbWVyZ2VfZmNkLnInKQoKCmRpciA9ICdkYi8wNi8wMScKdXVyMSA9IDYKdXVyMiA9IDE5Cgp0YWJlbF9vdmVyZGFnID0gbWVyZ2VfdGFibGVzKGRpciA9IGRpcix1dXIxID0gdXVyMSwgdXVyMiA9IHV1cjIpCnRhYmVsX25hY2h0ID0gIG1lcmdlX3RhYmxlcyhkaXIgPSBkaXIsdXVyMSA9IHV1cjIsIHV1cjIgPSB1dXIxKQoKYGBgCgoKCiMjdmluZCBkb29kbG9wZW5kZSB3ZWdlbgpFciBrb21lbiBzb21zIGtsZWluZSBvbnRlcmVjaHRlIGFmdGFra2luZ2VuIHZvb3IgaW4gaGV0IE5XQiBvbSBkaWUgb3AgdGUga3VubmVuIHNwb3JlbiB2ZXJnZWxpamtlbiB3ZSBleHBsZWNpZXQgZGUgZG9vZGxvcGVuZGUgd2VnZW4gdmFuIGhldCBOV0IgbWV0IGhldCBPU00uCgpgYGB7cn0KCgogIHJhbmQgPSBkYXRhLmZyYW1lKCd4Jz0gLTEsICd5JyA9IC0xKQoKIGZvcihpIGluIDE6bGVuZ3RoKG53Yl9zZWxlY3RAbGluZXMpKXsKCiAgICBuaWV1dyA9IG53Yl9zZWxlY3RAbGluZXNbW2ldXUBMaW5lc1tbMV1dQGNvb3JkcwogICAgY29sbmFtZXMobmlldXcpID0gYygneCcsJ3knKQogICAgcmFuZF9uaWV1dyA9IHJiaW5kKG5pZXV3WzEsXSAsbmlldXdbbnJvdyhuaWV1dyksXSkKICAgIAogICAgcmFuZCA9IHJiaW5kKHJhbmQsIHJhbmRfbmlldXcpCiAgCiB9CnJhbmQgPSByYW5kWy0xLF0KCmRvb2Rsb3BlbmRfbndiID0gcmFuZFshZHVwbGljYXRlZChyYW5kKSxdCgoKICByYW5kID0gZGF0YS5mcmFtZSgneCc9IC0xLCAneScgPSAtMSkKCiBmb3IoaSBpbiAxOmxlbmd0aChiYXNlbWFwX3NlbGVjdEBsaW5lcykpewoKICAgIG5pZXV3ID0gYmFzZW1hcF9zZWxlY3RAbGluZXNbW2ldXUBMaW5lc1tbMV1dQGNvb3JkcwogICAgY29sbmFtZXMobmlldXcpID0gYygneCcsJ3knKQogICAgcmFuZF9uaWV1dyA9IHJiaW5kKG5pZXV3WzEsXSAsbmlldXdbbnJvdyhuaWV1dyksXSkKICAgIAogICAgcmFuZCA9IHJiaW5kKHJhbmQsIHJhbmRfbmlldXcpCiAgCiB9CnJhbmQgPSByYW5kWy0xLF0KCmRvb2Rsb3BlbmRfb3NtID0gcmFuZFshZHVwbGljYXRlZChyYW5kKSxdCgoKCgpgYGAKCg==